package com.molichuxing.services.business.service.impl;

import com.moli.iov.util.Md5PwdEncoder;
import com.moli.iov.util.api.ApiUtils;
import com.molichuxing.framework.dto.Paged;
import com.molichuxing.framework.dto.TabDto;
import com.molichuxing.framework.exception.BizException;
import com.molichuxing.framework.result.ResponseCodeEnum;
import com.molichuxing.framework.utils.CollectionUtils;
import com.molichuxing.framework.utils.ObjectCastUtil;
import com.molichuxing.framework.utils.StringUtil;
import com.molichuxing.services.business.convertor.Convert;
import com.molichuxing.services.business.dto.request.CreateDealerSuperAccountDto;
import com.molichuxing.services.business.dto.request.SmartTerminalLoginDto;
import com.molichuxing.services.business.dto.request.UpdateDealerSuperAccountDto;
import com.molichuxing.services.business.dto.response.AccountLoginBizDto;
import com.molichuxing.services.business.service.AccountBizService;
import com.molichuxing.services.exception.PermissionExceptionCodeEnum;
import com.molichuxing.services.infrastructure.dto.response.response.*;
import com.molichuxing.services.infrastructure.service.*;
import com.molichuxing.services.property.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 账号组合服务
 *
 * @author zoumingyu
 * @date 2019年9月9日
 */
@Service("accountBizService")
public class AccountBizServiceImpl implements AccountBizService {
    private static final Logger logger = LoggerFactory.getLogger(AccountBizServiceImpl.class);

    @Resource
    private AccountService accountService;

    @Resource
    private AccountDealerService accountDealerService;

    @Resource
    private AccountGroupService accountGroupService;

    @Resource
    private GroupService groupService;

    @Resource
    private LoginLogService loginLogService;

    @Resource
    private ResourceService resourceService;

    @Resource
    private GroupResourceService groupResourceService;

    /**
     * 账号登录
     *
     * @param params account：账号 <br/>
     *               password：密码 <br/>
     *               systemType：系统类型-enum <br/>
     * @return
     */
    @Override
    public AccountLoginBizDto login(Map<String, Object> params) throws BizException {
        AccountLoginBizDto result = null;
        try {
            // 根据账号和密码查询账号信息
            AccountDto accountDto = accountService.getEffectiveAccount(ObjectCastUtil.castString(params.get("account")),
                    ObjectCastUtil.castString(params.get("password")),
                    ObjectCastUtil.castEmun(params.get("systemType"), SystemTypeEnum.class));

            result = Convert.toAccountLoginBizDto(accountDto);
            result.setLoginTime(LocalDateTime.now());


            // 判断系统类型
            if (SystemTypeEnum.DEALER.equals(accountDto.getSystemType())) {
                // 经销商系统登录，需要查询经销商id
                AccountDealerDto accountDealerDto = accountDealerService.getAccountDealer(accountDto.getId());
                if (accountDealerDto != null) {
                    result.setDealerId(accountDealerDto.getDealerId());
                }
            }

            GroupDto groupDto = null;
            int isSuper = (accountDto.getIsSuper() != null && accountDto.getIsSuper()) ? 1 : 0; //是否为超级管理员（经销商有超级管理员）
            if (accountDto.getSystemType().getValue() == SystemTypeEnum.DEALER.getValue()
                    && isSuper == SuperAccountEnum.YES.getValue()) { //超级管理员
                result.setGroupName("超级管理员");
            } else {
                //查询用户所属角色并赋值
                int groupId = 0;
                Map<String, Object> getAccountGroupParam = new HashMap<>();
                getAccountGroupParam.put("accountId", accountDto.getId());
                List<AccountGroupDto> accountGroupList = accountGroupService.getAccountGroupListByParam(getAccountGroupParam);
                if (CollectionUtils.isNotEmpty(accountGroupList)) {
                    groupId = accountGroupList.get(0).getGroupId(); //用户和角色是一对一关系
                }

                if (groupId > 0) {
                    groupDto = groupService.getGroupById(groupId);
                }

                if (groupDto == null) { //用户没有绑定角色
                    throw new BizException(PermissionExceptionCodeEnum.NOT_SYSTEM_PERMISSION.getCode(),
                            PermissionExceptionCodeEnum.NOT_SYSTEM_PERMISSION.getMessage());
                } else {
                    if (groupDto.getStatus() == StatusEnum.OFF.getValue()) {
                        throw new BizException(PermissionExceptionCodeEnum.NOT_SYSTEM_PERMISSION.getCode(),
                                PermissionExceptionCodeEnum.NOT_SYSTEM_PERMISSION.getMessage());
                    }
                    result.setGroupId(groupDto.getId());
                    result.setGroupName(groupDto.getGroupName());
                }
            }

            // 查询该账户上一次登录时间并记录当前登录时间
            LoginLogDto lastDataDto = loginLogService.getAccountByLastLoginTime(accountDto.getId(), LoginLogTypeEnum.LOGIN.getValue());
            if (lastDataDto != null) {
                result.setLastLoginTime(lastDataDto.getLoginTime());
            }

            // 登录成功，记录操作日志
            loginLogService.create(Convert.toLoginLogCreateDto(result, params, true, "登录成功"));
        } catch (Exception e) {
            logger.error("登录失败", e);
            try {
                // 异常失败，记录登录日志
                String resultExplain;
                if (e instanceof BizException) {
                    resultExplain = e.getMessage();
                } else {
                    resultExplain = "登录操作发生异常";
                }
                loginLogService.create(Convert.toLoginLogCreateDto(null, params, false, resultExplain));
            } catch (Exception ex) {
                logger.error("登录失败，记录登录日志异常", ex);
            }

            throw e;
        }

        return result;
    }

    /**
     * 账号登录
     *
     * @param params account：账号 <br/>
     *               password：密码 <br/>
     *               systemType：系统类型-enum <br/>
     * @return
     */
    @Override
    public AccountLoginBizDto loginByIov(Map<String, Object> params) throws BizException {
        AccountLoginBizDto result = null;
        // 根据账号和密码查询账号信息
        AccountDto accountDto = accountService.getEffectiveAccountByIov(ObjectCastUtil.castString(params.get("account")),
                ObjectCastUtil.castString(params.get("password")),
                ObjectCastUtil.castEmun(params.get("systemType"), SystemTypeEnum.class));

        result = Convert.toAccountLoginBizDto(accountDto);

        GroupDto groupDto = null;

        //查询用户所属角色并赋值
        int groupId = 0;
        Map<String, Object> getAccountGroupParam = new HashMap<>();
        getAccountGroupParam.put("accountId", accountDto.getId());
        List<AccountGroupDto> accountGroupList = accountGroupService.getAccountGroupListByParam(getAccountGroupParam);
        if (CollectionUtils.isNotEmpty(accountGroupList)) {
            groupId = accountGroupList.get(0).getGroupId(); //用户和角色是一对一关系
        }

        if (groupId > 0) {
            groupDto = groupService.getGroupById(groupId);
        }

        if (groupDto == null) { //用户没有绑定角色
            throw new BizException(PermissionExceptionCodeEnum.NOT_SYSTEM_PERMISSION.getCode(),
                    PermissionExceptionCodeEnum.NOT_SYSTEM_PERMISSION.getMessage());
        } else {
            if (groupDto.getStatus() == StatusEnum.OFF.getValue()) {
                throw new BizException(PermissionExceptionCodeEnum.NOT_SYSTEM_PERMISSION.getCode(),
                        PermissionExceptionCodeEnum.NOT_SYSTEM_PERMISSION.getMessage());
            }
            result.setGroupId(groupDto.getId());
            result.setGroupName(groupDto.getGroupName());
        }
        return result;
    }

    @Override
    public Paged<AccountDto> getAccountList(Map<String, Object> params, int pageNum, int pageSize) {
        //1,获取tab，并获取tab下用户总数
        //2,根据条件查询用户
        //3,查询用户绑定角色，并赋值给橘色

        //1
        //获取tab页以及tab页下用户数量
        List<TabDto> tabList = new ArrayList<>();
        Map<String, Object> getCountParam = new HashMap<>();
        for (TabEnum tabEnum : TabEnum.values()) {
            getCountParam.put("systemType", tabEnum.getValue());
            int tabCount = accountService.getAccountCount(getCountParam);

            TabDto tab = new TabDto();
            tab.setName(tabEnum.getName());
            tab.setType(tabEnum.getValue());
            tab.setCount(tabCount);
            tabList.add(tab);
        }

        //2
        List<AccountDealerDto> dealerList = null;
        if (params != null && Integer.parseInt(params.get("systemType").toString()) == SystemTypeEnum.DEALER.getValue() && params.get("dealerId") != null) { //经销商
            dealerList = accountDealerService.getAccountDealerByParam(params);
        }

        final List<Integer> accountIdList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(dealerList)) {
            dealerList.forEach(dealerDto -> {
                accountIdList.add(dealerDto.getAccountId());
            });
        }
        params.put("ids", accountIdList);

        Paged<AccountDto> accountPageList = accountService.getAccountList(params, pageNum, pageSize);

        //3
        if (accountPageList != null && CollectionUtils.isNotEmpty(accountPageList.getList())) {
            List<AccountDto> accountList = accountPageList.getList();
            if (CollectionUtils.isEmpty(accountIdList)) {
                accountList.forEach(accountDto -> {
                    accountIdList.add(accountDto.getId());
                });
            }

            Map<String, Object> getAccountGroupParam = new HashMap<>();
            getAccountGroupParam.put("accountIds", accountIdList);
            List<AccountGroupDto> accountGroupList = accountGroupService.getAccountGroupListByParam(getAccountGroupParam);

            final Map<Integer, GroupDto> accountBindGroupMap = new HashMap<>();
            if (CollectionUtils.isNotEmpty(accountGroupList)) {
                final List<Integer> groupIdList = new ArrayList<>();
                accountGroupList.forEach(accountGroup -> {
                    groupIdList.add(accountGroup.getGroupId());
                });

                Map<Integer, GroupDto> groupMap = null;
                if (CollectionUtils.isNotEmpty(groupIdList)) {
                    Map<String, Object> getGroupParam = new HashMap<>();
                    getGroupParam.put("ids", groupIdList);
                    getGroupParam.put("superGroup", -1);
                    List<GroupDto> groupList = groupService.getGroupListByParm(getGroupParam);
                    if (CollectionUtils.isNotEmpty(groupList)) {
                        groupMap = groupList.stream().collect(Collectors.toMap(GroupDto::getId, groupDto -> groupDto));
                    }
                }

                if (groupMap != null && groupMap.size() > 0) {
                    for (AccountGroupDto accountGroup : accountGroupList) {
                        accountBindGroupMap.put(accountGroup.getAccountId(), groupMap.get(accountGroup.getGroupId()));
                    }
                }
            }

            accountList.forEach(accountDto -> {
                GroupDto dto = null;
                if (accountBindGroupMap != null && (dto = accountBindGroupMap.get(accountDto.getId())) != null) {
                    accountDto.setGroupId(dto.getId());
                    accountDto.setGroupName(dto.getGroupName());
                } else if (accountDto.getSystemType().getValue() == SystemTypeEnum.DEALER.getValue() && accountDto.getIsSuper()) {
                    accountDto.setGroupName("超级管理员");
                }
            });
        }

        accountPageList.setTab(tabList);
        return accountPageList;
    }

    @Override
    public Paged<AccountDto> getAccountListByDealer(Map<String, Object> params, int pageNum, int pageSize) {

        //1
        Paged<AccountDto> accountPageList = null;

        List<AccountDealerDto> dealerList = accountDealerService.getAccountDealerByParam(params);
        if (CollectionUtils.isNotEmpty(dealerList)) {
            final List<Integer> accountIdList = new ArrayList<>();
            dealerList.forEach(dealerDto -> {
                accountIdList.add(dealerDto.getAccountId());
            });
            params.put("ids", accountIdList);

            accountPageList = accountService.getAccountList(params, pageNum, pageSize);

            //3
            if (accountPageList != null && CollectionUtils.isNotEmpty(accountPageList.getList())) {
                List<AccountDto> accountList = accountPageList.getList();
                if (CollectionUtils.isEmpty(accountIdList)) {
                    accountList.forEach(accountDto -> {
                        accountIdList.add(accountDto.getId());
                    });
                }

                Map<String, Object> getAccountGroupParam = new HashMap<>();
                getAccountGroupParam.put("accountIds", accountIdList);
                List<AccountGroupDto> accountGroupList = accountGroupService.getAccountGroupListByParam(getAccountGroupParam);

                final Map<Integer, GroupDto> accountBindGroupMap = new HashMap<>();
                if (CollectionUtils.isNotEmpty(accountGroupList)) {
                    final List<Integer> groupIdList = new ArrayList<>();
                    accountGroupList.forEach(accountGroup -> {
                        groupIdList.add(accountGroup.getGroupId());
                    });

                    Map<Integer, GroupDto> groupMap = null;
                    if (CollectionUtils.isNotEmpty(groupIdList)) {
                        Map<String, Object> getGroupParam = new HashMap<>();
                        getGroupParam.put("ids", groupIdList);
                        List<GroupDto> groupList = groupService.getGroupListByParm(getGroupParam);
                        if (CollectionUtils.isNotEmpty(groupList)) {
                            groupMap = groupList.stream().collect(Collectors.toMap(GroupDto::getId, groupDto -> groupDto));
                        }
                    }

                    if (groupMap != null && groupMap.size() > 0) {
                        for (AccountGroupDto accountGroup : accountGroupList) {
                            accountBindGroupMap.put(accountGroup.getAccountId(), groupMap.get(accountGroup.getGroupId()));
                        }
                    }
                }

                accountList.forEach(accountDto -> {
                    GroupDto dto = null;
                    if (accountBindGroupMap != null && accountBindGroupMap.size() > 0 && (dto = accountBindGroupMap.get(accountDto.getId())) != null) {
                        accountDto.setGroupId(dto.getId());
                        accountDto.setGroupName(dto.getGroupName());
                    } else if (accountDto.getSystemType().getValue() == SystemTypeEnum.DEALER.getValue() && accountDto.getIsSuper()) {
                        accountDto.setGroupName("超级管理员");
                    }
                });
            }
        }
        return accountPageList;
    }

    @Override
    @Transactional
    public int modifyAccount(AccountModifyDto dto) {
//        if (dto.getStatus() == StatusEnum.OFF.getValue()) { //用户被禁用
//            accountDealerService.deleteByAccountId(dto.getId()); //删除与经销商的关联关系
//            accountGroupService.deleteByAccountId(dto.getId()); //删除与角色的关联关系
//        }
        accountService.modifyAccount(dto);
        return 0;
    }

    /**
     * 获取经销商下的拥有智能终端的用户
     *
     * @return
     */
    @Override
    public List<AccountDto> getSmartTerminalAccountByDealer(int dealerId) {

        List<AccountDto> result = null;

        //查询用户和机构的关联表
        Map<String, Object> getAccountDealerParam = new HashMap<>();
        getAccountDealerParam.put("dealerId", dealerId);
        List<AccountDealerDto> accountDealerList = accountDealerService.getAccountDealerByParam(getAccountDealerParam);

        final List<Integer> accountIds = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(accountDealerList)) {
            accountDealerList.forEach(accountDealer -> {
                accountIds.add(accountDealer.getAccountId());
            });

            Map<String, Object> getAccountParam = new HashMap<>();
            getAccountParam.put("ids", accountIds);
            getAccountParam.put("status", StatusEnum.OPEN.getValue());
            getAccountParam.put("smartTerminal", SmartTerminalEnum.YES.getValue()); //是否拥有智能终端权限
            result = accountService.getAccountByParam(getAccountParam);
        }
        return result;
    }

    /**
     * 根据手机号判断经销商系统下是否存在对应的拥有智能终端登陆权限的用户
     *
     * @param id        用户id
     * @param userPhone 用户手机号
     * @return
     */
    @Override
    public AccountDto getSmartTerminalAccount(Integer id, String userPhone) {
        Boolean result = false;
        Map<String, Object> getAccountParam = new HashMap<>();
        getAccountParam.put("id", id);
        getAccountParam.put("systemType", SystemTypeEnum.DEALER.getValue());
        getAccountParam.put("userPhone", userPhone);
        getAccountParam.put("status", StatusEnum.OPEN.getValue());
        getAccountParam.put("smartTerminal", SmartTerminalEnum.YES.getValue()); //是否拥有智能终端权限
        List<AccountDto> dataList = accountService.getAccountByParam(getAccountParam);
        if (CollectionUtils.isNotEmpty(dataList)) {
            return dataList.get(0);
        }
        return null;
    }

    @Override
    public boolean smartTerminalLogin(SmartTerminalLoginDto dto) {
        if (dto == null) {
            throw new IllegalArgumentException("param  invalid");
        }
        if (dto.getId() <= 0) {
            throw new IllegalArgumentException("id  invalid");
        }
        if (StringUtil.isEmpty(dto.getUserPhone())) {
            throw new IllegalArgumentException("userPhone  invalid");
        }
        if (StringUtil.isEmpty(dto.getPassword())) {
            throw new IllegalArgumentException("password  invalid");
        }

        Map<String, Object> getAccountParam = new HashMap<>();
        getAccountParam.put("id", dto.getId());
        getAccountParam.put("userPhone", dto.getUserPhone());
        getAccountParam.put("status", StatusEnum.OPEN.getValue());
        getAccountParam.put("password", dto.getPassword()); //是否拥有智能终端权限
        List<AccountDto> dataList = accountService.getAccountByParam(getAccountParam);
        return CollectionUtils.isNotEmpty(dataList);
    }

    /**
     * 创建经销商下得超级管理员，以及超级管理员角色
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional
    public String createDealerSuperAccount(CreateDealerSuperAccountDto dto) {
        //1，创建用户
        //2，创建角色
        //3, 创建用户与经销商关联
        //4，创建用户与角色得关联
        //5，创建角色与权限的关联
        if (dto == null) {
            throw new NullPointerException("invalid param，param is null");
        }
        if (dto.getDealerId() <= 0) {
            throw new NullPointerException("invalid param，dealerId is null");
        }
        if (StringUtil.isEmpty(dto.getDealerEmail())) {
            throw new NullPointerException("invalid param，dealerEmail is null");
        }

        AccountDto account = accountService.getAccount(dto.getDealerEmail(), SystemTypeEnum.DEALER.getValue());
        if (account != null) {
            throw new BizException(ResponseCodeEnum.OPTION_ERROR.getCode(), "用户[" + dto.getDealerEmail() + "]已经存在");
        }

        String password = ApiUtils.generateNonceStrLower(8);

        AccountCreateDto superAccount = new AccountCreateDto();
        superAccount.setSystemType(SystemTypeEnum.DEALER.getValue());
        superAccount.setAccount(dto.getDealerEmail());
        superAccount.setRealName(dto.getDealerName());
        superAccount.setPasswordSalt(dto.getPasswordSalt());
        superAccount.setPassword(Md5PwdEncoder.encodePassword(password, dto.getPasswordSalt()));
        superAccount.setUserPhone(dto.getUserPhone());
        superAccount.setStatus(StatusEnum.OPEN.getValue());
        superAccount.setIsSuper(Boolean.TRUE);
        superAccount.setAccountAccount("系统");
        int accountId = accountService.createAccount(superAccount);
        if (accountId > 0) {//创建用户成功

            //创建用户与经销商关联
            AccountDealerDto accountDealerDto = new AccountDealerDto();
            accountDealerDto.setAccountId(accountId);
            accountDealerDto.setDealerId(dto.getDealerId());
            accountDealerService.createAccountDealer(accountDealerDto);

            return password;
        }
        return null;
    }

    /**
     * 禁用经销商下的所有用户
     *
     * @param dealerId
     * @return
     */
    @Override
    public boolean modifyAccountToDisableByDealerId(int dealerId) {
        if (dealerId <= 0) {
            throw new NullPointerException("param invalid，dealerId is null");
        }

        final List<Integer> accountIds = new ArrayList<>();

        Map<String, Object> getAccountDealerParam = new HashMap<>();
        getAccountDealerParam.put("dealerId", dealerId);
        List<AccountDealerDto> accountDealerList = accountDealerService.getAccountDealerByParam(getAccountDealerParam);
        if (CollectionUtils.isNotEmpty(accountDealerList)) {
            accountDealerList.forEach(accountDealer -> {
                accountIds.add(accountDealer.getAccountId());
            });

            if (CollectionUtils.isNotEmpty(accountIds)) {
                int row = accountService.modifyAccountToDisable(accountIds);
                return row == accountIds.size();
            }
        } else {
            return true;
        }
        return false;
    }

    @Override
    public int modifyAccountToOpenByDealerId(int dealerId) {
        if (dealerId <= 0) {
            throw new NullPointerException("param invalid，dealerId is null");
        }

        final List<Integer> accountIds = new ArrayList<>();

        Map<String, Object> getAccountDealerParam = new HashMap<>();
        getAccountDealerParam.put("dealerId", dealerId);
        List<AccountDealerDto> accountDealerList = accountDealerService.getAccountDealerByParam(getAccountDealerParam);
        if (CollectionUtils.isNotEmpty(accountDealerList)) {
            accountDealerList.forEach(accountDealer -> {
                accountIds.add(accountDealer.getAccountId());
            });
        }

        if (CollectionUtils.isNotEmpty(accountIds)) {
            return accountService.modifyAccountStatusToOpen(accountIds);
        }

        return 0;
    }

    @Override
    public String updateDealerSuperAccount(UpdateDealerSuperAccountDto dto) {
        if (dto.getId() <= 0) {
            throw new NullPointerException("param invalid，id is null");
        }

        Map<String, Object> getAccountDealerParam = new HashMap<>();
        getAccountDealerParam.put("dealerId", dto.getId());

        List<AccountDealerDto> accountDealerList = accountDealerService.getAccountDealerByParam(getAccountDealerParam);
        AccountDto account = null;
        if (CollectionUtils.isNotEmpty(accountDealerList)) {
            final List<Integer> accountIds = new ArrayList<>();
            accountDealerList.forEach(accountDealer -> {
                accountIds.add(accountDealer.getAccountId());
            });

            Map<String, Object> getAccountMap = new HashMap<>();
            getAccountMap.put("ids", accountIds);
            getAccountMap.put("super", SuperAccountEnum.YES.getValue());
            List<AccountDto> superAccountList = accountService.getAccountByParam(getAccountMap);
            if (CollectionUtils.isNotEmpty(superAccountList)) {
                account = superAccountList.get(0);
            }
        }

        if (account != null) {
            if (!account.getAccount().equals(dto.getEmail())) { //修改了邮箱
                AccountDto reAccount = accountService.getAccount(dto.getEmail(), SystemTypeEnum.DEALER.getValue());
                if (reAccount != null) { //用户已经存在
                    throw new BizException(ResponseCodeEnum.OPTION_ERROR.getCode(), "用户[" + dto.getEmail() + "]已经存在");
                }
            }

            AccountModifyDto modifyDto = Convert.toAccountModifyDto(account);
            String password = ApiUtils.generateNonceStrLower(8);
            modifyDto.setAccount(dto.getEmail());
            modifyDto.setPassword(Md5PwdEncoder.encodePassword(password, dto.getPasswordSalt()));

            accountService.modifyAccount(modifyDto);

            return password;
        } else {
            CreateDealerSuperAccountDto createDto = new CreateDealerSuperAccountDto();
            createDto.setDealerEmail(dto.getEmail());
            createDto.setDealerName(dto.getDealerName());
            createDto.setPasswordSalt(dto.getPasswordSalt());
            createDto.setDealerId(dto.getId());
            createDto.setUserPhone(dto.getUserPhone());
            return createDealerSuperAccount(createDto);
        }
    }

    @Override
    public AccountDto getAccountByDealer(String accountName) {
        AccountDto account = accountService.getAccount(accountName, SystemTypeEnum.DEALER.getValue());
        if (account != null) {
            AccountDealerDto accountDealer = accountDealerService.getAccountDealer(account.getId());
            if (accountDealer != null) {
                account.setDealerId(accountDealer.getDealerId());
            }
        }
        return account;
    }
}
